/*
 * Copyright (C), 2002-2016, 苏宁易购电子商务有限公司
 * FileName: ClusterManagementAction.java
 * Author:   admin
 * Date:     2016年1月6日 下午4:04:09
 * Description: //模块目的、功能描述      
 * History: //修改记录
 * <author>      <time>      <version>    <desc>
 * 修改人姓名             修改时间            版本号                  描述
 */
package com.suning.app.snpaasadmin.action;

import com.opensymphony.xwork2.ActionSupport;
import com.suning.app.snpaasadmin.api.ComponentApi;
import com.suning.app.snpaasadmin.api.DeploymentApi;
import com.suning.app.snpaasadmin.api.LoginApi;
import com.suning.app.snpaasadmin.domain.CfClusterExternal;
import com.suning.app.snpaasadmin.domain.ClusterDetail;
import com.suning.app.snpaasadmin.domain.ComponentConfig;
import com.suning.app.snpaasadmin.operation.CfClusterDBOperation;
import com.suning.app.snpaasadmin.pojo.CfCluster;
import com.suning.app.snpaasadmin.pojo.CfClusterConfig;
import com.suning.app.snpaasadmin.util.Constants;
import com.suning.app.snpaasadmin.util.JsonUtil;
import com.suning.app.snpaasadmin.util.StringUtil;

import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.apache.http.HttpHost;
import org.apache.http.protocol.HttpContext;
import org.apache.struts2.ServletActionContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.apache.log4j.Logger;

/**
 * 对集群的一系列操作<br>
 * 集群列表，集群新建，集群详情
 *
 * @author admin
 * @see [相关类/方法]（可选）
 * @since [产品/模块版本] （可选）
 */
@Controller
public class ClusterManagementAction extends ActionSupport {

    private static final long serialVersionUID = 1L;

    private Map<String, Object> dataMap;
    
    private Logger logger = Logger.getLogger(ClusterManagementAction.class);

    @Autowired
    private CfClusterDBOperation clusterDB;

    private String directorUuid;

    private String cfRelease;

    private String deploymentName;

    private String rootDomain;

    private String componentDomain;

    private String runingtimeDomain;

    private String networkId;

    private String components;

    private String sdfsAdderss;

    private String deployId;

    private String taskId;

    private Integer offset;

    private Integer type;
    
    private String clusterName;

    /**
     * 
     * 功能描述: <br>
     * 创建集群
     *
     * @return
     * @throws Exception
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public String createCluster() throws Exception {
        dataMap = new HashMap<String, Object>();
        Map<String, Object> input = new HashMap<String, Object>();
        HttpServletRequest request = ServletActionContext.getRequest();
        HttpSession session = request.getSession();
        HttpContext httpContext = (HttpContext) session.getAttribute(LoginAction.CFBASICAUTH);
        HttpHost httpHost = (HttpHost) session.getAttribute(LoginAction.CFAUTHHOST);

        // 根据传入的deployId查询数据
        List<CfClusterConfig> cfClusterConfigs = clusterDB.selectComponentConfig(deployId, null);
        List<CfCluster> cfClusters = clusterDB.getCfClusterAll(deployId);
        if (cfClusters != null && cfClusters.size() > 0) {
            input.put("director_uuid", cfClusters.get(0).getDirectorUuid());
            input.put("cf_release", cfClusters.get(0).getCfRelease());
            input.put("deployment_name", cfClusters.get(0).getClusterName());
            input.put("root_domain", cfClusters.get(0).getRootDomain());
            input.put("component_domain", cfClusters.get(0).getComponentDomain());
            input.put("runningtime_domain", cfClusters.get(0).getRuningtimeDomain());
            input.put("network_id", cfClusters.get(0).getNetworkId());
            input.put("sdfs_address", cfClusters.get(0).getSdfsAddress());
        }
        if (cfClusterConfigs != null && cfClusterConfigs.size() > 0) {
            for (CfClusterConfig config : cfClusterConfigs) {
                input.put(config.getComponent(), config);
            }
        }
        ServletContext sc = ServletActionContext.getServletContext();
        String filePath = DeploymentApi.generateyml(input, Constants.CLOUD_CLUSTER, logger, sc);
        String data = DeploymentApi.getyml(filePath);
        String taskId = DeploymentApi.deployCluster(httpContext, httpHost, data);

        clusterDB.insertTaskId(taskId, deployId, Constants.TYPE_CF_VERSION);

        // 更新部署状态
        if (cfClusters != null && cfClusters.size() > 0) {
            cfClusters.get(0).setStatus(Constants.CLUSTER_DEPLOY);
            cfClusters.get(0).setTaskId(taskId);
            cfClusters.get(0).setFilePath(filePath);
            clusterDB.updateClusterConfig(cfClusters.get(0));
        }
        Map<String, String> map = new HashMap<>();
        map.put("taskId", taskId);
        dataMap.put("data", map);
        dataMap.put("success", true);
        return SUCCESS;
    }

    /**
     * 
     * 功能描述: <br>
     * 保存修改配置
     *
     * @return
     * @throws Exception
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public String saveClusterConfig() throws Exception {
        dataMap = new HashMap<String, Object>();
        CfCluster cluster = new CfCluster();
        cluster.setCfRelease(cfRelease);
        cluster.setClusterName(deploymentName);
        cluster.setComponentDomain(componentDomain);
        cluster.setDirectorUuid(directorUuid);
        cluster.setNetworkId(networkId);
        cluster.setRootDomain(rootDomain);
        cluster.setRuningtimeDomain(runingtimeDomain);
        cluster.setStatus(Constants.CLUSTER_UNDEPLOY);
        cluster.setSdfsAddress(sdfsAdderss);

        // 当depolyId不为空，则说明是修改配置
        if (StringUtil.isNotEmpty(deployId) && StringUtil.isNotNullString(deployId)) {

            // 覆盖deployId下的配置
            cluster.setId(Integer.valueOf(deployId));
            cluster.setUpdateTime(new Date());
            clusterDB.updateClusterConfig(cluster);

            // 查询所有的组件 更新
            List<CfClusterConfig> cfClusterConfigs = clusterDB.selectComponentConfig(deployId, null);
            if (cfClusterConfigs != null && cfClusterConfigs.size() > 0) {
                for (CfClusterConfig comConfig : cfClusterConfigs) {
                    List<Map<String, Object>> temp = JsonUtil.convertJsonToList(components);
                    for (Map<String, Object> oneConfig : temp) {
                        if (comConfig.getComponent().equals(oneConfig.get("name").toString())) {
                            comConfig.setCount(Integer.valueOf(oneConfig.get("count").toString()));
                            comConfig.setCpuCore(Integer.valueOf(oneConfig.get("cpuCore").toString()));

                            comConfig.setCpuOverload(Boolean.valueOf(oneConfig.get("count").toString()));
                            comConfig.setMemorySize(oneConfig.get("memory").toString());
                            comConfig.setNetId(oneConfig.get("netId").toString());
                            clusterDB.updateComponentConfig(comConfig);
                        }
                    }
                }
            }
            Map<String, String> map = new HashMap<>();
            map.put("deployId", deployId);
            dataMap.put("data", map);
            dataMap.put("success", true);
            return SUCCESS;
        } else {
            cluster.setCreateTime(new Date());
            clusterDB.insertClusterConfig(cluster);
            Integer clusterId = cluster.getId();
            List<Map<String, Object>> temp = JsonUtil.convertJsonToList(components);
            for (Map<String, Object> oneConfig : temp) {
                CfClusterConfig clusterConfig = new CfClusterConfig();
                clusterConfig.setDeployId(clusterId);
                clusterConfig.setComponent(oneConfig.get("name").toString());
                clusterConfig.setCount(Integer.valueOf(oneConfig.get("count").toString()));
                clusterConfig.setCpuCore(Integer.valueOf(oneConfig.get("cpuCore").toString()));
                clusterConfig.setCpuOverload(Boolean.valueOf(oneConfig.get("count").toString()));
                clusterConfig.setMemorySize(oneConfig.get("memory").toString());
                clusterConfig.setNetId(oneConfig.get("netId").toString());
                clusterDB.insertComponentConfig(clusterConfig);
            }
            Map<String, String> map = new HashMap<>();
            map.put("deployId", String.valueOf(clusterId));
            dataMap.put("data", map);
            return SUCCESS;
        }
    }

    /**
     * 
     * 功能描述: <br>
     * 获取集群列表
     *
     * @return
     * @throws Exception
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public String listCluster() throws Exception {
        dataMap = new HashMap<String, Object>();
        HttpServletRequest request = ServletActionContext.getRequest();
        HttpSession session = request.getSession();
        HttpContext httpContext = (HttpContext) session.getAttribute(LoginAction.CFBASICAUTH);
        HttpHost httpHost = (HttpHost) session.getAttribute(LoginAction.CFAUTHHOST);

        // 列出所有的集群
        List<Map<String, Object>> deploys = DeploymentApi.getDeployments(httpContext, httpHost ,logger);

        // 从数据库中获取集群
        List<CfCluster> cfClusters = clusterDB.getCfClusterAll(null);
        List<CfClusterExternal> clusters = new ArrayList<CfClusterExternal>();
        if (deploys != null) {
            Map<String, Object> tmpMap = new HashMap<>();
            for (CfCluster cluster : cfClusters) {
                if (tmpMap.containsKey(cluster.getClusterName())) {
                    continue;
                }
                for (Map<String, Object> map : deploys) {
                    if (cluster.getClusterName().equals(map.get("name").toString())) {
                        // 查找集群状态
                        Map<String, Object> vms = ComponentApi.getVms(httpContext, httpHost, cluster.getClusterName());
                        // 根据taskId获取到状态
                        Integer taskId = (Integer) vms.get("id");
                        boolean flag = false;
                        while (!flag) {
                            Map<String, Object> tasks = ComponentApi.getTasks(httpContext, httpHost, taskId);
                            if (tasks.get("state").toString().equals("done")) {
                                flag = true;
                            }
                        }
                        if (flag == true) {
                            CfClusterExternal clusterExternal = new CfClusterExternal();
                            // boolean state = DeploymentApi.getClusterState(httpContext, httpHost, taskId);
                            /*
                             * if (state == false) { clusterExternal.setDeploymentName(cluster.getClusterName());
                             * clusterExternal.setDeployId(cluster.getId()); if (cluster.getCreateTime() != null) {
                             * clusterExternal.setCreateTime(cluster.getCreateTime().getTime()); } if
                             * (cluster.getUpdateTime() != null) {
                             * clusterExternal.setUpdateTime(cluster.getUpdateTime().getTime()); }
                             * clusterExternal.setStatus(Constants.CLUSTER_ERROR); } else {
                             * clusterExternal.setDeploymentName(cluster.getClusterName());
                             * clusterExternal.setDeployId(cluster.getId()); if (cluster.getCreateTime() != null) {
                             * clusterExternal.setCreateTime(cluster.getCreateTime().getTime()); } if
                             * (cluster.getUpdateTime() != null) {
                             * clusterExternal.setUpdateTime(cluster.getUpdateTime().getTime()); }
                             * clusterExternal.setStatus(cluster.getStatus()); }
                             */
                            clusterExternal.setDeploymentName(cluster.getClusterName());
                            clusterExternal.setDeployId(cluster.getId());
                            if (cluster.getCreateTime() != null) {
                                clusterExternal.setCreateTime(cluster.getCreateTime().getTime());
                            }
                            if (cluster.getUpdateTime() != null) {
                                clusterExternal.setUpdateTime(cluster.getUpdateTime().getTime());
                            }
                            clusterExternal.setStatus(cluster.getStatus());
                            tmpMap.put(cluster.getClusterName(), clusterExternal);
                        }
                    }
                }
                if (tmpMap.containsKey(cluster.getClusterName())) {
                    continue;
                }
                CfClusterExternal clusterExternal = new CfClusterExternal();
                clusterExternal.setDeploymentName(cluster.getClusterName());
                clusterExternal.setDeployId(cluster.getId());
                if (cluster.getCreateTime() != null) {
                    clusterExternal.setCreateTime(cluster.getCreateTime().getTime());
                }
                if (cluster.getUpdateTime() != null) {
                    clusterExternal.setUpdateTime(cluster.getUpdateTime().getTime());
                }
                clusterExternal.setStatus(cluster.getStatus());
                tmpMap.put(cluster.getClusterName(), clusterExternal);
            }
            
            // 遍历map
            for (Object value : tmpMap.values()) {
                clusters.add((CfClusterExternal) value);
            }
            dataMap.put("data", clusters);
            dataMap.put("success", true);
        } else {
            dataMap.put("data", null);
            dataMap.put("success", true);
        }
        return SUCCESS;
    }

    /**
     * 
     * 功能描述: <br>
     * 获取集群详情 即配置
     *
     * @param deployId
     * @return
     * @throws Exception
     * @see [相关类/方法](可选)
     * @since [产品/模块版本](可选)
     */
    public String getClusterDetail() throws Exception {
        dataMap = new HashMap<String, Object>();
        HttpServletRequest request = ServletActionContext.getRequest();
        HttpSession session = request.getSession();
        HttpContext httpContext = (HttpContext) session.getAttribute(LoginAction.CFBASICAUTH);
        HttpHost httpHost = (HttpHost) session.getAttribute(LoginAction.CFAUTHHOST);
        // 列出所有的集群
        List<Map<String, Object>> deploys = DeploymentApi.getDeployments(httpContext, httpHost, logger);

        // 从数据库中获取指定集群
        List<CfCluster> cfClusters = clusterDB.getCfClusterAll(deployId);
        ClusterDetail detail = new ClusterDetail();
        detail.setCfRelease(cfClusters.get(0).getCfRelease());
        detail.setComponentDomain(cfClusters.get(0).getComponentDomain());
        detail.setDeployId(deployId);
        detail.setDeploymentName(cfClusters.get(0).getClusterName());
        detail.setDirectorUuid(cfClusters.get(0).getDirectorUuid());
        detail.setNetworkId(cfClusters.get(0).getNetworkId());
        detail.setRootDomain(cfClusters.get(0).getRootDomain());
        detail.setRuningtimeDomain(cfClusters.get(0).getRuningtimeDomain());
        if (deploys != null) {
            for (Map<String, Object> map : deploys) {
                if (cfClusters != null && cfClusters.size() > 0) {
                    if (cfClusters.get(0).getClusterName().equals(map.get("name").toString())) {

                        // 查找集群状态
                        Map<String, Object> vms = ComponentApi.getVms(httpContext, httpHost,
                                cfClusters.get(0).getClusterName());
                        // 根据taskId获取到状态
                        Integer taskId = (Integer) vms.get("id");
                        boolean flag = false;
                        while (!flag) {
                            Map<String, Object> tasks = ComponentApi.getTasks(httpContext, httpHost, taskId);
                            if (tasks.get("state").toString().equals("done")) {
                                flag = true;
                            }
                        }
                        if (flag == true) {

                            // 从数据据中获取的数据
                            List<CfClusterConfig> cfClusterConfigs = clusterDB.selectComponentConfig(deployId, null);
                            List<ComponentConfig> comConfigs = new ArrayList<>();
                            if (cfClusterConfigs != null && cfClusterConfigs.size() > 0) {
                                for (CfClusterConfig comConfig : cfClusterConfigs) {
                                    ComponentConfig config = new ComponentConfig();
                                    config.setCount(comConfig.getCount());
                                    config.setName(comConfig.getComponent());
                                    config.setCpuCore(comConfig.getCpuCore());
                                    config.setOverload(Boolean.valueOf(comConfig.getCpuOverload()));
                                    config.setMemory(comConfig.getMemorySize());
                                    config.setNetId(comConfig.getNetId());
                                    comConfigs.add(config);
                                }
                            }
                            detail.setComponents(comConfigs);
                        }
                    } else {
                        List<CfClusterConfig> cfClusterConfigs = clusterDB.selectComponentConfig(deployId, null);
                        List<ComponentConfig> comConfigs = new ArrayList<>();
                        if (cfClusterConfigs != null && cfClusterConfigs.size() > 0) {
                            for (CfClusterConfig comConfig : cfClusterConfigs) {
                                ComponentConfig config = new ComponentConfig();
                                config.setCount(comConfig.getCount());
                                config.setName(comConfig.getComponent());
                                config.setCpuCore(comConfig.getCpuCore());
                                config.setOverload(Boolean.valueOf(comConfig.getCpuOverload()));
                                config.setMemory(comConfig.getMemorySize());
                                config.setNetId(comConfig.getNetId());
                                comConfigs.add(config);
                            }
                        }
                        detail.setComponents(comConfigs);
                    }
                }
            }
            dataMap.put("data", detail);
            dataMap.put("success", true);
        }
        return SUCCESS;
    }

    public String getClusterDeployLog() throws Exception {
        dataMap = new HashMap<String, Object>();
        HttpServletRequest request = ServletActionContext.getRequest();
        HttpSession session = request.getSession();
        HttpContext httpContext = (HttpContext) session.getAttribute(LoginAction.CFBASICAUTH);
        HttpHost httpHost = (HttpHost) session.getAttribute(LoginAction.CFAUTHHOST);
        Map<String, Object> data = DeploymentApi.getDeployingLog(taskId, offset, httpContext, httpHost);
        dataMap.put("data", data);
        dataMap.put("success", true);
        return SUCCESS;
    }

    private String filename;

    public InputStream getDownloadClusterLog() throws Exception {
        HttpServletRequest request = ServletActionContext.getRequest();
        HttpSession session = request.getSession();
        HttpContext httpContext = (HttpContext) session.getAttribute(LoginAction.CFBASICAUTH);
        HttpHost httpHost = (HttpHost) session.getAttribute(LoginAction.CFAUTHHOST);
        String data = DeploymentApi.downloadDeployLog(taskId, httpContext, httpHost);
        setFilename(taskId + ".log");
        return new ByteArrayInputStream(data.getBytes());

    }

    public void setFilename(String filename) {
        try {
            this.filename = new String(filename.getBytes("ISO8859-1"), "GBK");
        } catch (UnsupportedEncodingException e) {
        }
    }

    public String getFilename() {
        try {
            return new String(filename.getBytes(), "ISO8859-1");
        } catch (UnsupportedEncodingException e) {
            return this.filename;
        }
    }

    public String deleteCluster() throws Exception {
        dataMap = new HashMap<String, Object>();
        HttpServletRequest request = ServletActionContext.getRequest();
        HttpSession session = request.getSession();
        HttpContext httpContext = (HttpContext) session.getAttribute(LoginAction.CFBASICAUTH);
        HttpHost httpHost = (HttpHost) session.getAttribute(LoginAction.CFAUTHHOST);
        String name = clusterDB.getDeployName(deployId);
        DeploymentApi.deleteCfCluster(httpContext, httpHost, name);

        // 删除数据库记录
        clusterDB.deleteCfClusterData(deployId);
        dataMap.put("success", true);
        return SUCCESS;
    }

    public String getClusterDirectorUuid() throws Exception {
        dataMap = new HashMap<String, Object>();
        HttpServletRequest request = ServletActionContext.getRequest();
        HttpSession session = request.getSession();
        HttpContext httpContext = (HttpContext) session.getAttribute(LoginAction.CFBASICAUTH);
        HttpHost httpHost = (HttpHost) session.getAttribute(LoginAction.CFAUTHHOST);
        Map<String, Object> result = LoginApi.CheckLogin(httpContext, httpHost);
        Map<String, String> res = new HashMap<>();
        res.put("directorUuid", result.get("uuid").toString());
        dataMap.put("data", res);
        dataMap.put("success", true);
        return SUCCESS;
    }

    public String listTasksInfo() throws Exception {
        dataMap = new HashMap<String, Object>();
        dataMap.put("data", clusterDB.getTasksInfo(deployId, type));
        dataMap.put("success", true);
        return SUCCESS;
    }

    public String checkName() throws Exception {
        dataMap = new HashMap<String, Object>();
        Boolean isDup = true;
        List<CfCluster> cfClusters = clusterDB.getCfClusterAll("");
        for (CfCluster cluster : cfClusters) {
            if (clusterName.equals(cluster.getClusterName())) {
                isDup = false;
            }
        }
        dataMap.put("data", isDup);
        dataMap.put("success", true);
        return SUCCESS;
    }

    /**
     * @return the dataMap
     */
    public Map<String, Object> getDataMap() {
        return dataMap;
    }

    /**
     * @param dataMap the dataMap to set
     */
    public void setDataMap(Map<String, Object> dataMap) {
        this.dataMap = dataMap;
    }

    /**
     * @return the directorUuid
     */
    public String getDirectorUuid() {
        return directorUuid;
    }

    /**
     * @param directorUuid the directorUuid to set
     */
    public void setDirectorUuid(String directorUuid) {
        this.directorUuid = directorUuid;
    }

    /**
     * @return the cfRelease
     */
    public String getCfRelease() {
        return cfRelease;
    }

    /**
     * @param cfRelease the cfRelease to set
     */
    public void setCfRelease(String cfRelease) {
        this.cfRelease = cfRelease;
    }

    /**
     * @return the deploymentName
     */
    public String getDeploymentName() {
        return deploymentName;
    }

    /**
     * @param deploymentName the deploymentName to set
     */
    public void setDeploymentName(String deploymentName) {
        this.deploymentName = deploymentName;
    }

    /**
     * @return the rootDomain
     */
    public String getRootDomain() {
        return rootDomain;
    }

    /**
     * @param rootDomain the rootDomain to set
     */
    public void setRootDomain(String rootDomain) {
        this.rootDomain = rootDomain;
    }

    /**
     * @return the componentDomain
     */
    public String getComponentDomain() {
        return componentDomain;
    }

    /**
     * @param componentDomain the componentDomain to set
     */
    public void setComponentDomain(String componentDomain) {
        this.componentDomain = componentDomain;
    }

    /**
     * @return the runingtimeDomain
     */
    public String getRuningtimeDomain() {
        return runingtimeDomain;
    }

    /**
     * @param runingtimeDomain the runingtimeDomain to set
     */
    public void setRuningtimeDomain(String runingtimeDomain) {
        this.runingtimeDomain = runingtimeDomain;
    }

    /**
     * @return the networkId
     */
    public String getNetworkId() {
        return networkId;
    }

    /**
     * @param networkId the networkId to set
     */
    public void setNetworkId(String networkId) {
        this.networkId = networkId;
    }

    /**
     * @return the components
     */
    public String getComponents() {
        return components;
    }

    /**
     * @param components the components to set
     */
    public void setComponents(String components) {
        this.components = components;
    }

    /**
     * @return the sdfsAdderss
     */
    public String getSdfsAdderss() {
        return sdfsAdderss;
    }

    /**
     * @param sdfsAdderss the sdfsAdderss to set
     */
    public void setSdfsAdderss(String sdfsAdderss) {
        this.sdfsAdderss = sdfsAdderss;
    }

    /**
     * @return the deployId
     */
    public String getDeployId() {
        return deployId;
    }

    /**
     * @param deployId the deployId to set
     */
    public void setDeployId(String deployId) {
        this.deployId = deployId;
    }

    /**
     * @return the taskId
     */
    public String getTaskId() {
        return taskId;
    }

    /**
     * @param taskId the taskId to set
     */
    public void setTaskId(String taskId) {
        this.taskId = taskId;
    }

    /**
     * @return the offset
     */
    public Integer getOffset() {
        return offset;
    }

    /**
     * @param offset the offset to set
     */
    public void setOffset(Integer offset) {
        this.offset = offset;
    }

    /**
     * @return the type
     */
    public Integer getType() {
        return type;
    }

    /**
     * @param type the type to set
     */
    public void setType(Integer type) {
        this.type = type;
    }

    /**
     * @return the clusterName
     */
    public String getClusterName() {
        return clusterName;
    }

    /**
     * @param clusterName the clusterName to set
     */
    public void setClusterName(String clusterName) {
        this.clusterName = clusterName;
    }

}
